﻿using System;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Stages.Dispatcher;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using SPCAFContrib.ReSharper.Common;
using SPCAFContrib.ReSharper.Common.Attributes;
using SPCAFContrib.ReSharper.Common.Extensions;
using SPCAFContrib.ReSharper.Consts;
using SPCAFContrib.ReSharper.Inspection.Code.SPCAF;

[assembly: RegisterConfigurableSeverity(SPC050250Highlighting.CheckId,
  null,
  Consts.SPCAF_BEST_PRACTICES_GROUP,
  SPC050250Highlighting.CheckId + ": " + SPC050250Highlighting.Message,
  "Assign RowLimit for SPQuery within the limited range (default 1 to 2000).",
  Severity.WARNING,
  false, Internal = false)]

namespace SPCAFContrib.ReSharper.Inspection.Code.SPCAF
{
    [ElementProblemAnalyzer(new[] { typeof(IAssignmentExpression) },
        HighlightingTypes = new[] {typeof (SPC050250Highlighting)})]
    [Applicability(
        IDEProjectType.SP2010FarmSolution |
        IDEProjectType.SPSandbox |
        IDEProjectType.SP2013FarmSolution |
        IDEProjectType.SPServerAPIReferenced)]
    public class AssignSPQueryRowLimitInLimitedRange : ElementProblemAnalyzer<IAssignmentExpression>
    {
        protected override void Run(IAssignmentExpression element, ElementProblemAnalyzerData analyzerData,
            IHighlightingConsumer consumer)
        {
            IPsiSourceFile sourceFile = element.GetSourceFile();

            if (sourceFile != null)
            {
                if (sourceFile.HasExcluded(analyzerData.SettingsStore)) return;

                IProject project = sourceFile.GetProject();

                if (project != null)
                {
                    if (project.IsApplicableFor(this))
                    {
                        if (IsInvalid(element))
                        {
                            consumer.AddHighlighting(
                                new SPC050250Highlighting(element),
                                element.GetDocumentRange(),
                                element.GetContainingFile());
                        }
                    }
                }
            }
        }

        public static bool IsInvalid(IAssignmentExpression element)
        {
            bool result = false;

            IExpressionType expressionType = element.GetExpressionType();

            if (expressionType.IsResolved && element.Dest.IsResolvedAsPropertyUsage(ClrTypeKeys.SPQuery, new[] { "RowLimit" }) && element.Source != null && element.Source.ConstantValue.IsInteger())
            {
                int rowlimit = Convert.ToInt32(element.Source.ConstantValue.Value);
                result = rowlimit < 1 || rowlimit > 2000;
            }

            return result;
        }
        
    }
    
    [ConfigurableSeverityHighlighting(CheckId, CSharpLanguage.Name, OverlapResolve = OverlapResolveKind.NONE, ShowToolTipInStatusBar = true)]
    public class SPC050250Highlighting : IHighlighting
    {
        public const string CheckId = "SPC050250";
        public const string Message = "Assign RowLimit for SPQuery in limited range";

        public IExpression Element { get; private set; }

        public SPC050250Highlighting(IExpression element)
        {
            this.Element = element;
        }

        #region IHighlighting Members

        public string ToolTip
        {
            get
            {
                return String.Format("{0}: {1}", CheckId, Message);
            }
        }
        public string ErrorStripeToolTip
        {
            get { return ToolTip; }
        }

        public int NavigationOffsetPatch
        {
            get { return 0; }
        }

        public bool IsValid()
        {
            return this.Element != null && this.Element.IsValid();
        }

        #endregion
    }
}
